/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2004
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
*
* Author's email : insane@dees.ufmg.br
* Author's Website : http://www.dees.ufmg.br/insane
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package br.ufmg.dees.insane.model.xfemModel.geometryEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import br.ufmg.dees.insane.model.xfemModel.geometryDescription.StandardDescription;
import br.ufmg.dees.insane.util.IPoint3d;
import br.ufmg.dees.insane.util.xfem.Line;
import br.ufmg.dees.insane.util.xfem.Segment;

/**
 * @author Kelson Wolff
 *
 */
public class PiecewiseLinear extends GeometryEntity {
	
	/**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * The List holding each Vertex that belongs to this PiecewiseLinear GeometryEntity.
	 */
	private List<Vertex> vertexList;
	
	/**
	 * The List holding each Segment that belongs to this PiecewiseLinear GeometryEntity.
	 */
	private List<Segment> segmentList;

	/**
	 * 
	 */
	public PiecewiseLinear() {
		super();
		// TODO Auto-generated constructor stub
		this.myGeoDescription = new StandardDescription();
		this.vertexList = new ArrayList<Vertex>();
		this.segmentList = new ArrayList<Segment>();
	}

	/**
	 * @return Returns the segmentList.
	 */
	public List<Segment> getSegmentList() {
		if(this.segmentList.isEmpty())
			this.makeSegments();
		return segmentList;
	}

	/**
	 * @param segmentList The segmentList to set.
	 */
	public void setSegmentList(List<Segment> segmentList) {
		this.segmentList = segmentList;
	}
	
	/**
	 * Returns the IPoint3d associated with the Vertex of index i from 
	 * the List of vertices of this PiecewiseLinear GeometryEntity.
	 * @param i The position of the Vertex.
	 * @return The IPoint3d associated with the Vertex of index i from 
	 * the List of vertices of this PiecewiseLinear GeometryEntity.
	 */
	public IPoint3d getVertex(int i){
		double x = this.getVertexList().get(i).getCoordinates(0);
		double y = this.getVertexList().get(i).getCoordinates(1);
		IPoint3d point = new IPoint3d(x,y);
		return point;
	}
	
	/**
	 * 
	 * @param vertex
	 */
	public void setVertex(Vertex vertex){
		vertex.setMyParent(this);
		this.vertexList.add(vertex);
	}

	/**
	 * @return Returns the vertexList.
	 */
	public List<Vertex> getVertexList() {
		return vertexList;
	}

	/**
	 * @param vertexList The vertexList to set.
	 */
	public void setVertexList(List<Vertex> vertexList) {
		this.vertexList = vertexList;
	}

	@Override
	public boolean intersects(Segment s) {
		ListIterator segments = this.getSegmentList().listIterator();
		boolean ret = false;
		while(segments.hasNext()){
			Segment segment = (Segment) segments.next();
			Line line = new Line(segment.getFirstPoint(),segment.getVector());
			if(line.intersects(s)){
				ret = true;
			}	
		}
		return ret;
	}

	@Override
	public List<IPoint3d> intersection(Segment s) {
		List<IPoint3d> result = new ArrayList<IPoint3d>();
		ListIterator segments = this.getSegmentList().listIterator();
		while(segments.hasNext()){
			Segment seg = (Segment) segments.next();
			Line line = new Line(seg.getFirstPoint(),seg.getVector());
			if(line.intersects(s)){
				IPoint3d intersecPoint = line.intersection(s);
				if(seg.on(intersecPoint))
					result.add(intersecPoint);
			}	
		}
		return result;
	}

	public Segment getSegmentClosestTo(IPoint3d p){
		return null;
	}
	
	public double getSignedDistanceOfPoint(IPoint3d p){
		return 0;
	}
	
	public int getPositionComparedTo(IPoint3d p){
		return -1;
	}
	
	/**
	 * Defines the connected Segments of this PiecewiseLinear GeometryEntity
	 * from the vertices so that can use methods of Segment Class.
	 * @return The list of Segments
	 */
	public List<Segment> makeSegments(){
		if(this.getVertexList().size() >= 2){
			for(int i=0; i<(this.getVertexList().size() - 1); i++){
				int j = i;
				Segment seg = new Segment(this.getVertex(i),this.getVertex(++j));
				this.segmentList.add(seg);
			}
			return this.segmentList;
		}
		else{
			System.out.println("makeSegments() error: the method need 2 vertices at least!");
			return null;
		}		
	}
	
	/**
	 * Returns the segment that contains the crack tip.
	 * @param tip The crack tip.
	 * @return The segment that contains the crack tip.
	 */
	public Segment getSegmentContain(Vertex tip){
		Segment segmentContainTip = new Segment();
		
		double x = tip.getCoordinates(0);
		double y = tip.getCoordinates(1);
		IPoint3d point = new IPoint3d(x,y);
		
		//check first segment
		if(point.getX() ==  this.getSegmentList().get(0).getFirstPoint().getX() && 
		   point.getY() ==  this.getSegmentList().get(0).getFirstPoint().getY()){ //point is the first TIP
			Segment seg = new Segment(this.getVertex(1),this.getVertex(0));
			segmentContainTip = seg;
		}
		if(point.getX() == this.getSegmentList().get(0).getSecondPoint().getX() &&
		   point.getY() == this.getSegmentList().get(0).getSecondPoint().getY()){
			Segment seg = new Segment(this.getVertex(0),this.getVertex(1));
			segmentContainTip = seg;
		}
		
		//check last segment
		int lastSegmentIndex = this.getSegmentList().size() - 1;
		int lastVertexIndex = this.getVertexList().size() - 1;
		if(point.getX() == this.getSegmentList().get(lastSegmentIndex).getSecondPoint().getX() &&
		   point.getY() == this.getSegmentList().get(lastSegmentIndex).getSecondPoint().getY()){
			Segment seg = new Segment(this.getVertex(lastVertexIndex-1),this.getVertex(lastVertexIndex));
			segmentContainTip = seg;
		}
		return segmentContainTip;
	}
	
	/**
	 * Inserts the vertex v at initial position of the List of vertices
	 * belonging to this PiecewiseLinear GeometryEntity.
	 * @param v The vertex to insert.
	 */
	public void insertNewVertexInFront(Vertex v){
		this.vertexList.add(0,v);
	}
	
	/**
	 * Inserts the vertex v at last position of the List of vertices
	 * belonging to this PiecewiseLinear GeometryEntity.
	 * @param v The vertex to insert.
	 */
	public void insertNewVertexAtBack(Vertex v){
		this.vertexList.add(v);
	}
	
	/**
	 * Inserts the Segment s at initial position of the List of segments
	 * belonging to this PiecewiseLinear GeometryEntity.
	 * @param s The segment to insert.
	 */
	public void insertNewSegmentInFront(Segment s){
		this.segmentList.add(0,s);
	}
	
	/**
	 * Inserts the Segment s at last position of the List of segments
	 * belonging to this PiecewiseLinear GeometryEntity.
	 * @param s The segment to insert.
	 */
	public void insertNewSegmentAtBack(Segment s){
		this.segmentList.add(s);
	}
	
	/**
	 * Returns true if the provided IPoint3d p belong to this PiecewiseLinear
	 * GeometryEntity or false if it don't belong.
	 * @param p The provided point.
	 * @return True if the provided IPoint3d p belong to this PiecewiseLinear
	 * GeometryEntity or false if it don't belong.
	 */
	public boolean isBelongToMe(IPoint3d p){
		boolean found = false;
		for(int i=0; i<this.getSegmentList().size(); i++){
			if(this.getSegmentList().get(i).on(p)){
				found = true;
				i = this.getSegmentList().size();
			}
		}
		return found;
	}

}
